Skip to content

fix: scope DNS port-53 exemption to configured resolver IPs - #32

Merged
danbugs merged 2 commits into
mainfrom
fix/port53-bypass
May 15, 2026
Merged

fix: scope DNS port-53 exemption to configured resolver IPs#32
danbugs merged 2 commits into
mainfrom
fix/port53-bypass

Conversation

@danbugs

@danbugs danbugs commented May 15, 2026

Copy link
Copy Markdown
Contributor

Summary

NetworkPolicy::check() unconditionally allowed any connection where
addr.port() == 53, regardless of destination IP. A guest could bypass
AllowList or BlockList restrictions entirely by setting the destination port
to 53 — the guest controls this field via parse_sockaddr.

  • Added parse_resolv_conf() that reads /etc/resolv.conf for nameserver IPs
    (returns empty set on non-Unix)
  • Port 53 is now only exempted when the destination IP is a configured DNS
    resolver, for both AllowList and BlockList policies
  • 3 new tests; 2 old tests that asserted the broken behavior replaced

Test plan

  • test_port53_arbitrary_ip_blocked — non-resolver IP on port 53 denied
  • test_port53_real_resolver_allowed — actual resolv.conf IP on port 53 allowed
  • test_port53_blocklist_enforced — blocklisted IP denied even on port 53
  • All existing network policy tests pass

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens outbound network policy enforcement by removing the blanket “port 53 is always allowed” exemption and scoping DNS allowance to the host’s configured resolver IPs (from /etc/resolv.conf), preventing a guest from bypassing allow/block lists by choosing destination port 53.

Changes:

  • Added parse_resolv_conf() to parse nameserver IPs from /etc/resolv.conf (Unix; empty set otherwise).
  • Updated NetworkPolicy::check() to exempt port 53 only when the destination IP is a configured resolver.
  • Updated/added tests to reflect the new port-53 behavior.
Comments suppressed due to low confidence (1)

host/src/lib.rs:349

  • In NetworkPolicy::BlockList, the port-53 resolver exemption is checked before bl.is_blocked(), which means a blocklisted resolver IP will still be allowed on port 53. If blocklist entries are intended to be enforced regardless of port (as the tests/documentation suggest), check bl.is_blocked(&addr.ip()) first and only apply the DNS exemption for non-blocked IPs (or remove the exemption for blocklist entirely).
            NetworkPolicy::BlockList(bl) => {
                // Allow DNS (port 53) only to configured resolver IPs.
                if addr.port() == 53 && parse_resolv_conf().contains(&addr.ip()) {
                    return Ok(());
                }
                if bl.is_blocked(&addr.ip()) {
                    Err(anyhow!("network policy denies connection to {}", addr))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread host/src/lib.rs Outdated
Comment on lines +335 to +336
if (addr.port() == 53 && parse_resolv_conf().contains(&addr.ip()))
|| al.is_allowed(&addr.ip())
Comment thread host/src/lib.rs Outdated
Comment on lines +306 to +322
fn parse_resolv_conf() -> HashSet<IpAddr> {
#[cfg(unix)]
{
let mut resolvers = HashSet::new();
if let Ok(contents) = std::fs::read_to_string("/etc/resolv.conf") {
for line in contents.lines() {
let line = line.trim();
if let Some(rest) = line.strip_prefix("nameserver") {
if let Some(ip_str) = rest.split_whitespace().next() {
if let Ok(ip) = ip_str.parse::<IpAddr>() {
resolvers.insert(ip);
}
}
}
}
}
resolvers
Comment thread host/src/lib.rs
Comment on lines +2653 to +2662
fn test_port53_arbitrary_ip_blocked() {
// Only 1.1.1.1 is in the allowlist — 8.8.8.8:53 must be denied
// because 8.8.8.8 is (almost certainly) not in /etc/resolv.conf.
let al = AllowList::from_hosts(&["1.1.1.1"]).unwrap();
let policy = NetworkPolicy::AllowList(al);
let addr: std::net::SocketAddr = "8.8.8.8:53".parse().unwrap();
assert!(
policy.check(&addr).is_err(),
"port 53 to a non-resolver IP must be denied"
);
Comment thread host/src/lib.rs
Comment on lines 2731 to +2740
#[test]
fn network_policy_blocklist_allows_dns() {
fn network_policy_blocklist_denies_blocked_ip_on_port53() {
// A blocked IP must not be exempted just because the port is 53.
let bl = BlockList::from_hosts(&["1.2.3.4"]).unwrap();
let policy = NetworkPolicy::BlockList(bl);
let addr: std::net::SocketAddr = "1.2.3.4:53".parse().unwrap();
assert!(policy.check(&addr).is_ok());
assert!(
policy.check(&addr).is_err(),
"blocked IP 1.2.3.4 must be denied even on port 53"
);
Comment thread host/src/lib.rs Outdated
Comment on lines 344 to 347
// Allow DNS (port 53) only to configured resolver IPs.
if addr.port() == 53 && parse_resolv_conf().contains(&addr.ip()) {
return Ok(());
}

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux Benchmarks

Details
Benchmark suite Current: 82fdb86 Previous: f5eb506 Ratio
hello_world (median) 20 ms 20 ms 1
pandas (median) 100 ms 110 ms 0.91
density (per VM) 7 MB 7 MB 1
snapshot (disk) 385 MiB 385 MiB 1

This comment was automatically generated by workflow using github-action-benchmark.

danbugs added 2 commits May 15, 2026 06:07
Signed-off-by: danbugs <danilochiarlone@gmail.com>
…ST-NET IPs in tests

Signed-off-by: danbugs <danilochiarlone@gmail.com>
@danbugs
danbugs force-pushed the fix/port53-bypass branch from cd92f68 to 82fdb86 Compare May 15, 2026 06:07

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows Benchmarks

Details
Benchmark suite Current: 82fdb86 Previous: f5eb506 Ratio
hello_world (median) 260 ms 221 ms 1.18
pandas (median) 827 ms 697 ms 1.19
density (per VM) 6 MB 6 MB 1
snapshot (disk) 393 MiB 393 MiB 1

This comment was automatically generated by workflow using github-action-benchmark.

@danbugs
danbugs merged commit b230d50 into main May 15, 2026
79 checks passed
@danbugs
danbugs deleted the fix/port53-bypass branch May 15, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants